/*
 * Copyright (c) 2013 WDCY Information Technology Co. Ltd
 * www.wdcy.cc
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of
 * WDCY Information Technology Co. Ltd ("Confidential Information").
 * You shall not disclose such Confidential Information and shall use
 * it only in accordance with the terms of the license agreement you
 * entered into with WDCY Information Technology Co. Ltd.
 */
package com.monkey.web.platform.service.impl;

import com.monkey.core.domain.permission.Permission;
import com.monkey.core.domain.resource.Menu;
import com.monkey.core.plugin.domain.Status;
import com.monkey.core.plugin.dto.MonkeyDto;
import com.monkey.core.plugin.service.BaseTreeableServiceImpl;
import com.monkey.web.platform.service.MenuService;
import com.monkey.web.platform.service.UserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.permission.WildcardPermission;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * @author Wu Tianqiang
 */
@Service
public class MenuServiceImpl extends BaseTreeableServiceImpl<Menu, Long> implements MenuService {

    @Autowired
    private UserService userService;

    @Override
    public void addMenu(MonkeyDto monkeyDto) {
        Long parentId = monkeyDto.getLong("parentId");
        Menu parentMenu = findOne(parentId);
        Menu menu = new Menu();
        menu.setName(monkeyDto.getString("name"));
        menu.setIdentity(monkeyDto.getString("identity"));
        menu.setView(monkeyDto.getString("view"));
        menu.setIcon(monkeyDto.getString("icon"));
        menu.setWeight(monkeyDto.getInteger("weight"));
        menu.setExpand(monkeyDto.getBoolean("expand"));
        menu.setStatus(Status.valueOf(monkeyDto.getString("status")));
        appendChild(parentMenu, menu);
    }

    @Override
    public void modifyMenu(MonkeyDto monkeyDto) {
        Long parentId = monkeyDto.getLong("parentId");
        Menu parent = findOne(parentId);
        Menu menu = findOne(monkeyDto.getLong("id"));
        menu.setName(monkeyDto.getString("name"));
        menu.setIdentity(monkeyDto.getString("identity"));
        menu.setView(monkeyDto.getString("view"));
        menu.setIcon(monkeyDto.getString("icon"));
        menu.setExpand(monkeyDto.getBoolean("expand"));
        menu.setStatus(Status.valueOf(monkeyDto.getString("status")));
        updateSelfAndChild(menu, parentId, parent.makeSelfAsNewParentIds(), monkeyDto.getInteger("weight"));
    }

    @Override
    public void removeMenu(Long[] menuIds) {
        for (Long menuId : menuIds) {
            Menu menu = findOne(menuId);
            deleteSelfAndChild(menu);
        }
    }


    public String findActualMenuIdentity(Menu menu) {
        if (menu == null) {
            return null;
        }
        StringBuilder s = new StringBuilder(menu.getIdentity());
        boolean hasMenuIdentity = !StringUtils.isEmpty(menu.getIdentity());

        Menu parent = findOne(menu.getParentId());
        while (parent != null) {
            if (!StringUtils.isEmpty(parent.getIdentity())) {
                s.insert(0, parent.getIdentity() + Permission.PART_DIVIDER_TOKEN);
                hasMenuIdentity = true;
            }
            parent = findOne(parent.getParentId());
        }

        //如果用户没有声明 资源标识  且父也没有，那么就为空
        if (!hasMenuIdentity) {
            return "";
        }

        //如果最后一个字符是: 因为不需要，所以删除之
        int length = s.length();
        if (length > 0 && s.lastIndexOf(Permission.PART_DIVIDER_TOKEN) == length - 1) {
            s.deleteCharAt(length - 1);
        }

//        //如果有儿子 最后拼一个*
//        boolean hasChildren = false;
//        for(Resource r : findAll()) {
//            if(resource.getId().equals(r.getParentId())) {
//                hasChildren = true;
//                break;
//            }
//        }
//        if(hasChildren) {
//            s.append(":*");
//        }

        return s.toString();
    }


    @Override
    public List<Menu> findChildByParent(Long parentId, boolean containDisable) {
        List<Menu> menus = new ArrayList<>();
        List<Menu> allMenus = super.findChildByParent(parentId, containDisable);
        Subject subject = SecurityUtils.getSubject();
        Long userId = (Long) subject.getPrincipal();
        Set<String> permissions = userService.findPermissions(userId);
        for (Menu menu : allMenus) {
            String identity = findActualMenuIdentity(menu);
            if (hasPermission(permissions, identity)) {
                menus.add(menu);
            }
        }
        return menus;
    }


    public boolean hasPermission(Set<String> permissions, String actualResourceIdentity) {
        if (StringUtils.isEmpty(actualResourceIdentity)) {
            return true;
        }

        for (String permission : permissions) {
            if (hasPermission(permission, actualResourceIdentity)) {
                return true;
            }
        }
        return false;
    }

    public boolean hasPermission(String permission, String actualResourceIdentity) {
        //得到权限字符串中的 资源部分，如a:b:create --->资源是a:b
        String permissionResourceIdentity = permission.substring(0, permission.lastIndexOf(":"));

        //如果权限字符串中的资源 是 以资源为前缀 则有权限 如a:b 具有a:b的权限
        if (permissionResourceIdentity.startsWith(actualResourceIdentity)) {
            return true;
        }

        //模式匹配
        WildcardPermission p1 = new WildcardPermission(permissionResourceIdentity);
        WildcardPermission p2 = new WildcardPermission(actualResourceIdentity);

        return p1.implies(p2) || p2.implies(p1);
    }
}